package com.zyd.blog.file;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Region;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringUtils;
import com.zyd.blog.file.entity.VirtualFile;
import com.zyd.blog.file.exception.JiayuanApiException;
import com.zyd.blog.file.exception.QiniuApiException;
import com.zyd.blog.file.jiayuanoss.UploadResponse;
import com.zyd.blog.file.util.FileUtil;
import com.zyd.blog.file.util.HttpClient;
import com.zyd.blog.file.util.StreamUtil;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Qiniu云操作文件的api：v1
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @version 1.0
 * @date 2018/4/16 16:26
 * @since 1.0
 */
public class JiayuanApiClient extends BaseApiClient {

    private static final String DEFAULT_PREFIX = "jiayuanblog/";

    private String accessKey;
    private String secretKey;
    private String bucket;
    private String authUrl;
    private String path;
    private String pathPrefix;
    private InputStream inputStream;

    private static ContentType IMAGE_BMP = ContentType.create("image/bmp", Charset.forName("UTF-8"));
    private static ContentType IMAGE_GIF = ContentType.create("image/gif", Charset.forName("UTF-8"));
    private static ContentType IMAGE_JPEG = ContentType.create("image/jpeg", Charset.forName("UTF-8"));
    private static ContentType IMAGE_PNG = ContentType.create("image/png", Charset.forName("UTF-8"));
    private static ContentType IMAGE_SVG = ContentType.create("image/svg+xml", Charset.forName("UTF-8"));
    private static ContentType IMAGE_TIFF = ContentType.create("image/tiff", Charset.forName("UTF-8"));
    private static ContentType IMAGE_WEBP = ContentType.create("image/webp", Charset.forName("UTF-8"));

    public static final Map<String, ContentType> IMAGE_TYPE;
    static {
        IMAGE_TYPE = new HashMap<String, ContentType>();
        IMAGE_TYPE.put(".png", IMAGE_PNG);
        IMAGE_TYPE.put(".gif", IMAGE_GIF);
        IMAGE_TYPE.put(".jpg", IMAGE_JPEG);
        IMAGE_TYPE.put(".jpeg", IMAGE_JPEG);
        IMAGE_TYPE.put(".bmp", IMAGE_BMP);
        IMAGE_TYPE.put(".svg", IMAGE_SVG);
        IMAGE_TYPE.put(".tiff", IMAGE_TIFF);
        IMAGE_TYPE.put(".webp", IMAGE_WEBP);
    }

    public JiayuanApiClient() {
        super("家园OSS");
    }

    public JiayuanApiClient init(String accessKey, String secretKey, String bucketName, String baseAuthUrl, String baseUrl, String uploadType) {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        this.bucket = bucketName;
        this.authUrl = baseAuthUrl;
        this.path = baseUrl;
        this.pathPrefix = StringUtils.isNullOrEmpty(uploadType) ? DEFAULT_PREFIX : uploadType.endsWith("/") ? uploadType : uploadType + "/";
        return this;
    }

    /**
     * 上传图片
     *
     * @param file       图片
     * @param imageUrl 图片路径
     * @return 上传后的路径
     */
    @Override
    public VirtualFile uploadImg(MultipartFile file, String imageUrl) {
        this.check();
        try {
            this.inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String key = FileUtil.generateTempFileName(imageUrl);
        Date startTime = new Date();
        String upToken = getToken(this.accessKey, this.secretKey);
        if(org.springframework.util.StringUtils.isEmpty(upToken)) {
            throw new JiayuanApiException("[" + this.storageType + "]文件上传失败：无此权限");
        }
        InputStream fileHashIs = StreamUtil.clone(this.inputStream);
        String response = upload(this.bucket, "", upToken, file);

        //解析上传成功的结果
        UploadResponse putRet = JSON.parseObject(response, UploadResponse.class);

        try {
            return new VirtualFile()
                    .setOriginalFileName(key)
                    .setSuffix(this.suffix)
                    .setUploadStartTime(startTime)
                    .setUploadEndTime(new Date())
                    .setFilePath(putRet.data.successFile.get(0))
                    .setFileHash(DigestUtils.md5DigestAsHex(fileHashIs))
                    .setFullFilePath(this.path + putRet.data.successFile.get(0));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 上传图片
     *
     * @param is       图片流
     * @param imageUrl 图片路径
     * @return 上传后的路径
     */
    @Override
    public VirtualFile uploadImg(InputStream is, String imageUrl) {
        this.check();

        String key = FileUtil.generateTempFileName(imageUrl);
        Date startTime = new Date();
        String upToken = getToken(this.accessKey, this.secretKey);
        if(org.springframework.util.StringUtils.isEmpty(upToken)) {
            throw new JiayuanApiException("[" + this.storageType + "]文件上传失败：无此权限");
        }
        InputStream fileHashIs = StreamUtil.clone(is);
        String response = upload(this.bucket, "", upToken, is, imageUrl);

        //解析上传成功的结果
        UploadResponse putRet = JSON.parseObject(response, UploadResponse.class);

        try {
            return new VirtualFile()
                    .setOriginalFileName(key)
                    .setSuffix(this.suffix)
                    .setUploadStartTime(startTime)
                    .setUploadEndTime(new Date())
                    .setFilePath(putRet.data.successFile.get(0))
                    .setFileHash(DigestUtils.md5DigestAsHex(fileHashIs))
                    .setFullFilePath(this.path + putRet.data.successFile.get(0));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除家园空间图片方法
     *
     * @param key 家园空间中文件名称
     */
    @Override
    public boolean removeFile(String key) {
        this.check();

        if (StringUtils.isNullOrEmpty(key)) {
            throw new QiniuApiException("[" + this.storageType + "]删除文件失败：文件key为空");
        }
        Auth auth = Auth.create(this.accessKey, this.secretKey);
        Configuration config = new Configuration(Region.autoRegion());
        BucketManager bucketManager = new BucketManager(auth, config);
        try {
            Response re = bucketManager.delete(this.bucket, key);
            return re.isOK();
        } catch (IOException e) {
            String r = e.getMessage();
            throw new JiayuanApiException("[" + this.storageType + "]删除文件发生异常：" + r);
        }
    }

    @Override
    public void check() {
        if (StringUtils.isNullOrEmpty(this.accessKey) || StringUtils.isNullOrEmpty(this.secretKey) || StringUtils.isNullOrEmpty(this.bucket)) {
            throw new JiayuanApiException("[" + this.storageType + "]尚未配置家园OSS，文件上传功能暂时不可用！");
        }
    }

    public String getPath() {
        return this.path;
    }

    private String getToken(String accessKey, String secretKey) {
        JSONObject requestBody = new JSONObject();
        JSONObject result;
        String url = this.authUrl + "authoriz/getToken";
        requestBody.put("appId", accessKey);
        requestBody.put("appSecret", secretKey);
        String token = HttpClient.post(requestBody,url);
        result = JSONObject.parseObject(token);
        if(result != null) {
            return result.getString("data");
        }
        return null;
    }
    private String upload(String bucket, String id, String token, MultipartFile file) {
        String url = this.path + "fileUploadBolg";
        Map<String, String> paramsMap = new HashMap();
        paramsMap.put("appId", accessKey);
        paramsMap.put("bucket", bucket);

        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
        ContentType strContent = ContentType.create("text/plain", Charset.forName("UTF-8"));
        ContentType imageContent = ContentType.create("image/jpeg");
        builder.addTextBody("appId", accessKey, strContent);
        builder.addTextBody("bucketName", bucket, strContent);
        builder.addTextBody("token", token, strContent);
        builder.addTextBody("platformId", id, strContent);

        String fileName = file.getOriginalFilename();
        try {
            String suffix = FileUtil.getSuffix(fileName);
            if(FileUtil.isPicture(suffix)) {
                builder.addBinaryBody("file", file.getInputStream(),IMAGE_TYPE.get(suffix), fileName);
            }else {
                builder.addBinaryBody("file", file.getInputStream(),ContentType.DEFAULT_BINARY, fileName);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //ContentType.MULTIPART_FORM_DATA
        HttpEntity parameterEntity = builder.build();
        httpPost.setEntity(parameterEntity);

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int code = response.getStatusLine().getStatusCode();
        if (code != 200) {
            try {
                throw new Exception(String.valueOf(code) + "&" + response.getStatusLine().getReasonPhrase());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        HttpEntity resultEntity = response.getEntity();
        if (resultEntity == null) {
            try {
                throw new Exception("response null");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String result = null;
        try {
            result = EntityUtils.toString(resultEntity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("发送成功：" + result);
        return result;
    }

    private String upload(String bucket, String id, String token, InputStream is, String originalFilename) {
        String url = this.path + "fileUploadBolg";
        Map<String, String> paramsMap = new HashMap();
        paramsMap.put("appId", accessKey);
        paramsMap.put("bucket", bucket);

            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
            ContentType strContent = ContentType.create("text/plain", Charset.forName("UTF-8"));
            builder.addTextBody("appId", accessKey, strContent);
            builder.addTextBody("bucketName", bucket, strContent);
            builder.addTextBody("token", token, strContent);
            builder.addTextBody("platformId", id, strContent);
            String suffix = FileUtil.getSuffix(originalFilename);
            if(FileUtil.isPicture(suffix)) {
                builder.addBinaryBody("file", is,IMAGE_TYPE.get(suffix), originalFilename);
            }else {
                builder.addBinaryBody("file", is,ContentType.DEFAULT_BINARY, originalFilename);
            }

            HttpEntity parameterEntity = builder.build();
            httpPost.setEntity(parameterEntity);

            CloseableHttpResponse response = null;
            try {
                response = httpclient.execute(httpPost);
            } catch (IOException e) {
                e.printStackTrace();
            }
            int code = response.getStatusLine().getStatusCode();
            if (code != 200) {
                try {
                    throw new Exception(String.valueOf(code) + "&" + response.getStatusLine().getReasonPhrase());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            HttpEntity resultEntity = response.getEntity();
            if (resultEntity == null) {
                try {
                    throw new Exception("response null");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            String result = null;
            try {
                result = EntityUtils.toString(resultEntity, "UTF-8");
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("发送成功：" + result);
            return result;
    }
}
